home *** CD-ROM | disk | FTP | other *** search
/ United Public Domain Gold 4 / United Public Domain Gold 4.iso / fredfish / ff.0065.dms / ff.0065.adf / Bawk / bawk.c < prev    next >
C/C++ Source or Header  |  1987-04-04  |  11KB  |  640 lines

  1. /*
  2.  * Bawk main program
  3.  */
  4. #define MAIN 1
  5. #include <stdio.h>
  6. #include "bawk.h"
  7.  
  8. /*
  9.  * Main program
  10.  */
  11. main( argc, argv )
  12. int argc;
  13. char **argv;
  14. {
  15.     char gotrules, didfile, getstdin;
  16.  
  17.     getstdin =
  18.     didfile =
  19.     gotrules = 0;
  20.  
  21.     /*
  22.      * Initialize global variables:
  23.      */
  24.     Beginact = 0;
  25.     Endact = 0;
  26.     Rules = 0;
  27.     Rulep = 0;
  28. #ifdef DEBUG
  29.     Debug = 0;
  30. #endif
  31.     Filename = 0;
  32.     Linecount = 0;
  33.     Saw_break = 0;
  34.     Stackptr = Stackbtm - 1;
  35.     Stacktop = Stackbtm + MAXSTACKSZ;
  36.     Nextvar = Vartab;
  37.  
  38.     strcpy( Fieldsep, " \t" );
  39.     strcpy( Recordsep, "\n" );
  40.  
  41.     /*
  42.      * Parse command line
  43.      */
  44.     while ( --argc )
  45.     {
  46.         if ( **(++argv) == '-' )
  47.         {
  48.             /*
  49.              * Process dash options.
  50.              */
  51.             switch ( tolower( *(++(*argv)) ) )
  52.             {
  53. #ifdef DEBUG
  54.             case 'd':
  55.                 ++Debug;
  56.                 break;
  57. #endif
  58.             case 0:
  59.                 ++getstdin;
  60.                 --argv;
  61.                 goto dosomething;
  62.                 break;
  63.             default: usage();
  64.             }
  65.         }
  66.         else
  67.         {
  68. dosomething:
  69.             if ( gotrules )
  70.             {
  71.                 /*
  72.                  * Already read rules file - assume this is
  73.                  * is a text file for processing.
  74.                  */
  75.                 if ( ++didfile == 1 && Beginact )
  76.                     doaction( Beginact );
  77.                 if ( getstdin )
  78.                 {
  79.                     --getstdin;
  80.                     newfile( 0 );
  81.                 }
  82.                 else
  83.                     newfile( *argv );
  84.                 process();
  85.             }
  86.             else
  87.             {
  88.                 /*
  89.                  * First file name argument on command line
  90.                  * is assumed to be a rules file - attempt to
  91.                  * compile it.
  92.                  */
  93.                 if ( getstdin )
  94.                 {
  95.                     --getstdin;
  96.                     newfile( 0 );
  97.                 }
  98.                 else
  99.                     newfile( *argv );
  100.                 compile();
  101.                 gotrules = 1;
  102.             }
  103.         }
  104.     }
  105.     if ( !gotrules )
  106.         usage();
  107.  
  108.     if ( ! didfile )
  109.     {
  110.         /*
  111.          * Didn't process any files yet - process stdin.
  112.          */
  113.         newfile( 0 );
  114.         if ( Beginact )
  115.             doaction( Beginact );
  116.         process();
  117.     }
  118.     if ( Endact )
  119.         doaction( Endact );
  120. }
  121.  
  122. /*
  123.  * Regular expression/action file compilation routines.
  124.  */
  125. compile()
  126. {
  127.     /*
  128.      * Compile regular expressions and C actions into Rules struct,
  129.      * reading from current input file "Fileptr".
  130.      */
  131.     int c, len;
  132.  
  133. #ifdef DEBUG
  134.     if ( Debug )
  135.         error( "compiling...", 0 );
  136. #endif
  137.  
  138.     while ( (c = getcharacter()) != -1 )
  139.     {
  140.         if ( c==' ' || c=='\t' || c=='\n' )
  141.             /* swallow whitespace */
  142.             ;
  143.         else if ( c=='#' )
  144.         {
  145.             /*
  146.              * Swallow comments
  147.              */
  148.             while ( (c=getcharacter()) != -1 && c!='\n' )
  149.                 ;
  150.         }
  151.         else if ( c=='{' )
  152.         {
  153. #ifdef DEBUG
  154.             if ( Debug )
  155.                 error( "action", 0 );
  156. #endif
  157.             /*
  158.              * Compile (tokenize) the action string into our
  159.              * global work buffer, then allocate some memory
  160.              * for it and copy it over.
  161.              */
  162.             ungetcharacter( '{' );
  163.             len = act_compile( Workbuf );
  164.  
  165.             if ( Rulep && Rulep->action )
  166.             {
  167.                 Rulep->nextrule = getmem( sizeof( *Rulep ) );
  168.                 Rulep = Rulep->nextrule;
  169.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  170.             }
  171.             if ( !Rulep )
  172.             {
  173.                 /*
  174.                  * This is the first action encountered.
  175.                  * Allocate the first Rules structure and
  176.                  * initialize it
  177.                  */
  178.                 Rules = Rulep = getmem( sizeof( *Rulep ) );
  179.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  180.             }
  181.             Rulep->action = getmem( len );
  182.             movemem( Workbuf, Rulep->action, len );
  183.         }
  184.         else if ( c==',' )
  185.         {
  186. #ifdef DEBUG
  187.             if ( Debug )
  188.                 error( "stop pattern", 0 );
  189. #endif
  190.             /*
  191.              * It's (hopefully) the second part of a two-part
  192.              * pattern string.  Swallow the comma and start
  193.              * compiling an action string.
  194.              */
  195.             if ( !Rulep || !Rulep->pattern.start )
  196.                 error( "stop pattern without a start",
  197.                     RE_ERROR );
  198.             if ( Rulep->pattern.stop )
  199.                 error( "already have a stop pattern",
  200.                     RE_ERROR );
  201.             len = pat_compile( Workbuf );
  202.             Rulep->pattern.stop = getmem( len );
  203.             movemem( Workbuf, Rulep->pattern.stop, len );
  204.         }
  205.         else
  206.         {
  207.             /*
  208.              * Assume it's a regular expression pattern
  209.              */
  210. #ifdef DEBUG
  211.             if ( Debug )
  212.                 error( "start pattern", 0 );
  213. #endif
  214.  
  215.             ungetcharacter( c );
  216.             len = pat_compile( Workbuf );
  217.  
  218.             if ( *Workbuf == T_BEGIN )
  219.             {
  220.                 /*
  221.                  * Saw a "BEGIN" keyword - compile following
  222.                  * action into special "Beginact" buffer.
  223.                  */
  224.                 len = act_compile( Workbuf );
  225.                 Beginact = getmem( len );
  226.                 movemem( Workbuf, Beginact, len );
  227.                 continue;
  228.             }
  229.             if ( *Workbuf == T_END )
  230.             {
  231.                 /*
  232.                  * Saw an "END" keyword - compile following
  233.                  * action into special "Endact" buffer.
  234.                  */
  235.                 len = act_compile( Workbuf );
  236.                 Endact = getmem( len );
  237.                 movemem( Workbuf, Endact, len );
  238.                 continue;
  239.             }
  240.             if ( Rulep )
  241.             {
  242.                 /*
  243.                  * Already saw a pattern/action - link in
  244.                  * another Rules structure.
  245.                  */
  246.                 Rulep->nextrule = getmem( sizeof( *Rulep ) );
  247.                 Rulep = Rulep->nextrule;
  248.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  249.             }
  250.             if ( !Rulep )
  251.             {
  252.                 /*
  253.                  * This is the first pattern encountered.
  254.                  * Allocate the first Rules structure and
  255.                  * initialize it
  256.                  */
  257.                 Rules = Rulep = getmem( sizeof( *Rulep ) );
  258.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  259.             }
  260.             if ( Rulep->pattern.start )
  261.                 error( "already have a start pattern",
  262.                     RE_ERROR );
  263.  
  264.             Rulep->pattern.start = getmem( len );
  265.             movemem( Workbuf, Rulep->pattern.start, len );
  266.         }
  267.     }
  268.     endfile();
  269. }
  270.  
  271. /*
  272.  * Text file main processing loop.
  273.  */
  274. process()
  275. {
  276.     /*
  277.      * Read a line at a time from current input file at "Fileptr",
  278.      * then apply each rule in the Rules chain to the input line.
  279.      */
  280.     int i;
  281.  
  282. #ifdef DEBUG
  283.     if ( Debug )
  284.         error( "processing...", 0 );
  285. #endif
  286.  
  287.     Recordcount = 0;
  288.  
  289.     while ( getline() )
  290.     {
  291.         /*
  292.          * Parse the input line.
  293.          */
  294.         Fieldcount = parse( Linebuf, Fields, Fieldsep );
  295. #ifdef DEBUG
  296.         if ( Debug>1 )
  297.         {
  298.             printf( "parsed %d words:\n", Fieldcount );
  299.             for(i=0; i<Fieldcount; ++i )
  300.                 printf( "<%s>\n", Fields[i] );
  301.         }
  302. #endif
  303.  
  304.         Rulep = Rules;
  305.         do
  306.         {
  307.             if ( ! Rulep->pattern.start )
  308.             {
  309.                 /*
  310.                  * No pattern given - perform action on
  311.                  * every input line.
  312.                  */
  313.                 doaction( Rulep->action );
  314.             }
  315.             else if ( Rulep->pattern.startseen )
  316.             {
  317.                 /*
  318.                  * Start pattern already found - perform
  319.                  * action then check if line matches
  320.                  * stop pattern.
  321.                  */
  322.                 doaction( Rulep->action );
  323.                 if ( dopattern( Rulep->pattern.stop ) )
  324.                     Rulep->pattern.startseen = 0;
  325.             }
  326.             else if ( dopattern( Rulep->pattern.start ) )
  327.             {
  328.                 /*
  329.                  * Matched start pattern - perform action.
  330.                  * If a stop pattern was given, set "start
  331.                  * pattern seen" flag and process every input
  332.                  * line until stop pattern found.
  333.                  */
  334.                 doaction( Rulep->action );
  335.                 if ( Rulep->pattern.stop )
  336.                     Rulep->pattern.startseen = 1;
  337.             }
  338.         }
  339.         while ( Rulep = Rulep->nextrule );
  340.  
  341.         /*
  342.          * Release memory allocated by parse().
  343.          */
  344.         while ( Fieldcount )
  345.             free( Fields[ --Fieldcount ] );
  346.     }
  347. }
  348.  
  349. /*
  350.  * Miscellaneous functions
  351.  */
  352. parse( str, wrdlst, delim )
  353. char *str;
  354. char *wrdlst[];
  355. char *delim;
  356. {
  357.     /*
  358.      * Parse the string of words in "str" into the word list at "wrdlst".
  359.      * A "word" is a sequence of characters delimited by one or more
  360.      * of the characters found in the string "delim".
  361.      * Returns the number of words parsed.
  362.      * CAUTION: the memory for the words in "wrdlst" is allocated
  363.      * by malloc() and should eventually be returned by free()...
  364.      */
  365.     int wrdcnt, wrdlen;
  366.     char wrdbuf[ MAXLINELEN ], c;
  367.  
  368.     wrdcnt = 0;
  369.     while ( *str )
  370.     {
  371.         while ( instr( *str, delim ) )
  372.             ++str;
  373.         if ( !*str )
  374.             break;
  375.         wrdlen = 0;
  376.         while ( (c = *str) && !instr( c, delim ) )
  377.         {
  378.             wrdbuf[ wrdlen++ ] = c;
  379.             ++str;
  380.         }
  381.         wrdbuf[ wrdlen++ ] = 0;
  382.         /*
  383.          * NOTE: allocate a MAXLINELEN sized buffer for every
  384.          * word, just in case user wants to copy a larger string
  385.          * into a field.
  386.          */
  387.         wrdlst[ wrdcnt ] = getmem( MAXLINELEN );
  388.         strcpy( wrdlst[ wrdcnt++ ], wrdbuf );
  389.     }
  390.  
  391.     return wrdcnt;
  392. }
  393.  
  394. unparse( wrdlst, wrdcnt, str, delim )
  395. char *wrdlst[];
  396. int wrdcnt;
  397. char *str;
  398. char *delim;
  399. {
  400.     /*
  401.      * Replace all the words in "str" with the words in "wrdlst",
  402.      * maintaining the same word seperation distance as found in
  403.      * the string.
  404.      * A "word" is a sequence of characters delimited by one or more
  405.      * of the characters found in the string "delim".
  406.      */
  407.     int wc;
  408.     char strbuf[ MAXLINELEN ], *sp, *wp, *start;
  409.  
  410.     wc = 0;        /* next word in "wrdlst" */
  411.     sp = strbuf;    /* points to our local string */
  412.     start = str;    /* save start address of "str" for later... */
  413.     while ( *str )
  414.     {
  415.         /*
  416.          * Copy the field delimiters from the original string to
  417.          * our local version.
  418.          */
  419.         while ( instr( *str, delim ) )
  420.             *sp++ = *str++;
  421.         if ( !*str )
  422.             break;
  423.         /*
  424.          * Skip over the field in the original string and...
  425.          */
  426.         while ( *str && !instr( *str, delim ) )
  427.             ++str;
  428.  
  429.         if ( wc < wrdcnt )
  430.         {
  431.             /*
  432.              * ...copy in the field in the wordlist instead.
  433.              */
  434.             wp = wrdlst[ wc++ ];
  435.             while ( *wp )
  436.                 *sp++ = *wp++;
  437.         }
  438.     }
  439.     /*
  440.      * Tie off the local string, then copy it back to caller's string.
  441.      */
  442.     *sp = 0;
  443.     strcpy( start, strbuf );
  444. }
  445.  
  446. instr( c, s )
  447. char c, *s;
  448. {
  449.     while ( *s )
  450.         if ( c==*s++ )
  451.             return 1;
  452.     return 0;
  453. }
  454.  
  455. char *
  456. getmem( len )
  457. unsigned len;
  458. {
  459.     char *cp;
  460.  
  461.     if ( cp=malloc( len ) )
  462.         return cp;
  463.     error( "out of memory", MEM_ERROR );
  464. }
  465.  
  466. char *newfile( s )
  467. char *s;
  468. {
  469.     Linecount = 0;
  470.     if ( Filename = s )
  471.     {
  472. #ifdef BDS_C
  473.         if ( fopen( s, Fileptr = Curfbuf ) == -1 )
  474. #else
  475.         if ( !(Fileptr = fopen( s, "r" )) )
  476. #endif
  477.             error( "file not found", FILE_ERROR );
  478.     }
  479.     else
  480.     {
  481.         /*
  482.          * No file name given - process standard input.
  483.          */
  484.         Fileptr = stdin;
  485.         Filename = "standard input";
  486.     }
  487. }
  488.  
  489. getline()
  490. {
  491.     /*
  492.      * Read a line of text from current input file.  Strip off
  493.      * trailing record seperator (newline).
  494.      */
  495.     int rtn, len;
  496.  
  497.     for ( len=0; len<MAXLINELEN; ++len )
  498.     {
  499.         if ( (rtn = getcharacter()) == *Recordsep || rtn == -1 )
  500.             break;
  501.         Linebuf[ len ] = rtn;
  502.     }
  503.     Linebuf[ len ] = 0;
  504.  
  505.     if ( rtn == -1 )
  506.     {
  507.         endfile();
  508.         return 0;
  509.     }
  510.     return 1;
  511. }
  512.  
  513. getcharacter()
  514. {
  515.     /*
  516.      * Read a character from curren input file.
  517.      * WARNING: your getc() must convert lines that end with CR+LF
  518.      * to LF and CP/M's EOF character (^Z) to a -1.
  519.      * Also, getc() must return a -1 when attempting to read from
  520.      * an unopened file.
  521.      */
  522.     int c;
  523.  
  524. #ifdef BDS_C
  525.     /*
  526.      * BDS C doesn't do CR+LF to LF and ^Z to -1 conversions <gag>
  527.      */
  528.     if ( (c = getc( Fileptr )) == '\r' )
  529.     {
  530.         if ( (c = getc( Fileptr )) != '\n' )
  531.         {
  532.             ungetc( c );
  533.             c = '\r';
  534.         }
  535.     }
  536.     else if ( c == 26 )    /* ^Z */
  537.         c = -1;
  538. #else
  539.     c = getc( Fileptr );
  540. #endif
  541.  
  542.     if ( c == *Recordsep )
  543.         ++Recordcount;
  544.     if ( c=='\n' )
  545.         ++Linecount;
  546.  
  547.     return c;
  548. }
  549.  
  550. ungetcharacter( c )
  551. {
  552.     /*
  553.      * Push a character back into the input stream.
  554.      * If the character is a record seperator, or a newline character,
  555.      * the record and line counters are adjusted appropriately.
  556.      */
  557.     if ( c == *Recordsep )
  558.         --Recordcount;
  559.     if ( c=='\n' )
  560.         --Linecount;
  561.     return ungetc( c, Fileptr );
  562. }
  563.  
  564. endfile()
  565. {
  566.     fclose( Fileptr );
  567.     Filename = Linecount = 0;
  568. }
  569.  
  570. error( s, severe )
  571. char *s;
  572. int severe;
  573. {
  574.     char *cp, *errat;
  575.  
  576.     if ( Filename )
  577.         fprintf( stderr, "%s:", Filename );
  578.  
  579.     if ( Linecount )
  580.         fprintf( stderr, " line %d:", Linecount );
  581.  
  582.     fprintf( stderr, " %s\n", s );
  583.     if ( severe )
  584.         exit( severe );
  585. }
  586.  
  587. usage()
  588. {
  589.     error( "Usage: bawk <actfile> [<file> ...]\n", USAGE_ERROR );
  590. }
  591.  
  592. movemem( from, to, count )
  593. char *from, *to;
  594. int count;
  595. {
  596.     while ( count-- > 0 )
  597.         *to++ = *from++;
  598. }
  599.  
  600. fillmem( array, count, value )
  601. char *array, value;
  602. int count;
  603. {
  604.     while ( count-- > 0 )
  605.         *array++ = value;
  606. }
  607.  
  608. strncmp( s, t, n )
  609. char *s, *t;
  610. int n;
  611. {
  612.     while ( --n>0 && *s && *t && *s==*t )
  613.     {
  614.         ++s;
  615.         ++t;
  616.     }
  617.     if ( *s || *t )
  618.         return *s - *t;
  619.     return 0;
  620. }
  621.  
  622. num( c )
  623. char c;
  624. {
  625.     return '0'<=c && c<='9';
  626. }
  627.  
  628. alpha( c )
  629. char c;
  630. {
  631.     return ('a'<=c && c<='z') || ('A'<=c && c<='Z') || c=='_';
  632. }
  633.  
  634. alphanum( c )
  635. char c;
  636. {
  637.     return alpha( c ) || num( c );
  638. }
  639.  
  640.